home *** CD-ROM | disk | FTP | other *** search
- #define LIBQBUILD_CORE
- #include "../include/libqbuild.h"
-
- /*
- *
- * NOTES
- * -----
- * Brushes that touch still need to be split at the cut point to make a tjunction
- *
- */
-
- struct visfacet **validfaces;
-
- struct visfacet *inside, *outside; // 8
- int brushfaces; // 4
- int csgfaces; // 4
- int csgmergefaces; // 4
-
- void DrawList(register struct visfacet * list)
- {
- for (; list; list = list->next)
- Draw_DrawFace(list);
- }
-
- /*
- * ==================
- * NewFaceFromFace
- *
- * Duplicates the non point information of a face, used by SplitFace and
- * MergeFace.
- * ==================
- */
- struct visfacet *NewFaceFromFace(register struct visfacet * in, register int points)
- {
- struct visfacet *newf;
-
- newf = AllocFace(points);
-
- newf->planenum = in->planenum;
- newf->texturenum = in->texturenum;
- newf->planeside = in->planeside;
- newf->original = in->original;
- newf->contents[0] = in->contents[0];
- newf->contents[1] = in->contents[1];
-
- return newf;
- }
-
- /*
- * ==================
- * SplitFace
- *
- * ==================
- */
- void SplitFace(struct visfacet * in, struct plane * split, struct visfacet ** front, struct visfacet ** back)
- {
- //vec_t dists[MAXEDGES + 1];
- //int sides[MAXEDGES + 1];
- vec_t *dists = (vec_t *)tmalloc(MAXEDGES * sizeof(vec_t));
- int *sides = (int *)tmalloc(MAXEDGES * sizeof(int));
- int counts[3];
- vec_t dot;
- int i, j;
- struct visfacet *newf, *new2;
- vec_t *p1, *p2;
- vec3_t mid;
-
- if (in->numpoints < 0)
- Error("SplitFace: freed face");
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i = 0; i < in->numpoints; i++) {
- dot = DotProduct(in->pts[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- sides[i] = SIDE_ON;
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (!counts[0]) {
- *front = NULL;
- *back = in;
- tfree(dists);
- tfree(sides);
- return;
- }
- if (!counts[1]) {
- *front = in;
- *back = NULL;
- tfree(dists);
- tfree(sides);
- return;
- }
-
- *back = newf = NewFaceFromFace(in, MAXEDGES);
- *front = new2 = NewFaceFromFace(in, MAXEDGES);
-
- // distribute the points and generate splits
-
- for (i = 0; i < in->numpoints; i++) {
- if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
- Error("SplitFace: numpoints > MAXEDGES");
-
- p1 = in->pts[i];
-
- if (sides[i] == SIDE_ON) {
- VectorCopy(p1, newf->pts[newf->numpoints]);
- newf->numpoints++;
- VectorCopy(p1, new2->pts[new2->numpoints]);
- new2->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT) {
- VectorCopy(p1, new2->pts[new2->numpoints]);
- new2->numpoints++;
- }
- else {
- VectorCopy(p1, newf->pts[newf->numpoints]);
- newf->numpoints++;
- }
-
- if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->pts[(i + 1) % in->numpoints];
-
- dot = dists[i] / (dists[i] - dists[i + 1]);
- for (j = 0; j < 3; j++) { // avoid round off error when possible
-
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot * (p2[j] - p1[j]);
- }
-
- VectorCopy(mid, newf->pts[newf->numpoints]);
- newf->numpoints++;
- VectorCopy(mid, new2->pts[new2->numpoints]);
- new2->numpoints++;
- }
-
- if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
- Error("SplitFace: numpoints > MAXEDGES");
-
- RecalcFace(newf);
- RecalcFace(new2);
- //if ((newf->numpoints > in->numpoints) || (new2->numpoints > in->numpoints))
- // mprintf("SplitFace: heavy split (%d to %d + %d)\n", in->numpoints, newf->numpoints, new2->numpoints);
-
- #if 0
- CheckFace(newf);
- CheckFace(new2);
- #endif
-
- // free the original face now that is is represented by the fragments
- FreeFace(in);
- tfree(dists);
- tfree(sides);
- }
-
- /*
- * =================
- * ClipInside
- *
- * Clips all of the faces in the inside list, possibly moving them to the
- * outside list or spliting it into a piece in each list.
- *
- * Faces exactly on the plane will stay inside unless overdrawn by later brush
- *
- * frontside is the side of the plane that holds the outside list
- * =================
- */
- void ClipInside(__memBase, register int splitplane, register int frontside, register bool precedence)
- {
- struct visfacet *f, *next;
- struct visfacet *frags[2];
- struct visfacet *insidelist;
- struct plane *split;
-
- #ifdef EXHAUSIVE_CHECK
- if(splitplane >= bspMem->numbrushplanes || splitplane < 0)
- Error("looking for nonexisting plane %d\n", splitplane);
- #endif
- split = &bspMem->brushplanes[splitplane];
-
- insidelist = NULL;
- for (f = inside; f; f = next) {
- next = f->next;
-
- if (f->planenum == splitplane) { // exactly on, handle special
-
- if (frontside != f->planeside || precedence) { // allways clip off opposite faceing
-
- frags[frontside] = NULL;
- frags[!frontside] = f;
- }
- else { // leave it on the outside
-
- frags[frontside] = f;
- frags[!frontside] = NULL;
- }
- }
- else { // proper split
-
- SplitFace(f, split, &frags[0], &frags[1]);
- }
-
- if (frags[frontside]) {
- frags[frontside]->next = outside;
- outside = frags[frontside];
- }
- if (frags[!frontside]) {
- frags[!frontside]->next = insidelist;
- insidelist = frags[!frontside];
- }
- }
-
- inside = insidelist;
- }
-
- /*
- * ==================
- * SaveOutside
- *
- * Saves all of the faces in the outside list to the bsp plane list
- * ==================
- */
- void SaveOutside(__memBase, register bool mirror)
- {
- struct visfacet *f, *next, *newf;
- int i;
- int planenum;
-
- for (f = outside; f; f = next) {
- next = f->next;
- csgfaces++;
- Draw_DrawFace(f);
- planenum = f->planenum;
-
- if (mirror) {
- newf = NewFaceFromFace(f, f->numpoints);
-
- newf->numpoints = f->numpoints;
- newf->planeside = f->planeside ^ 1; // reverse side
-
- newf->contents[0] = f->contents[1];
- newf->contents[1] = f->contents[0];
-
- for (i = 0; i < f->numpoints; i++) // add points backwards
- {
- VectorCopy(f->pts[f->numpoints - 1 - i], newf->pts[i]);
- }
- }
- else
- newf = NULL;
-
- validfaces[planenum] = MergeFaceToList(bspMem, f, validfaces[planenum]);
- if (newf)
- validfaces[planenum] = MergeFaceToList(bspMem, newf, validfaces[planenum]);
-
- validfaces[planenum] = FreeMergeListScraps(validfaces[planenum]);
- }
- }
-
- /*
- * ==================
- * FreeInside
- *
- * Free all the faces that got clipped out
- * ==================
- */
- void FreeInside(register int contents)
- {
- struct visfacet *f, *next;
-
- for (f = inside; f; f = next) {
- next = f->next;
-
- if (contents != CONTENTS_SOLID) {
- f->contents[0] = contents;
- f->next = outside;
- outside = f;
- }
- else
- FreeFace(f);
- }
- }
-
- //==========================================================================
-
- /*
- * ==================
- * BuildSurfaces
- *
- * Returns a chain of all the external surfaces with one or more visible
- * faces.
- * ==================
- */
- struct surface *BuildSurfaces(__memBase)
- {
- struct visfacet **f;
- struct visfacet *count;
- int i;
- struct surface *s;
- struct surface *surfhead;
-
- surfhead = NULL;
-
- f = validfaces;
- for (i = 0; i < bspMem->numbrushplanes; i++, f++) {
- if (*f) { // !nothing left on this plane
- // create a new surface to hold the faces on this plane
- s = AllocSurface();
- s->planenum = i;
- s->next = surfhead;
- surfhead = s;
- s->faces = *f;
- for (count = s->faces; count; count = count->next)
- csgmergefaces++;
- CalcSurfaceInfo(s); // bounding box and flags
- }
- /** mprogress(bspMem->numbrushplanes, i + 1); **/
- }
-
- return surfhead;
- }
-
- //==========================================================================
-
- /*
- * ==================
- * CopyFacesToOutside
- * ==================
- */
- void CopyFacesToOutside(register struct brush * b)
- {
- struct visfacet *f, *newf;
-
- outside = NULL;
-
- for (f = b->faces; f; f = f->next) {
- brushfaces++;
- #if 0
- {
- int i;
-
- for (i = 0; i < f->numpoints; i++)
- mprintf("(%f,%f,%f) ", f->pts[i][0], f->pts[i][1], f->pts[i][2]);
- mprintf("\n");
- }
- #endif
- newf = AllocFace(f->numpoints);
- CopyFace(newf, f);
- newf->next = outside;
- newf->contents[0] = CONTENTS_EMPTY;
- newf->contents[1] = b->contents;
- outside = newf;
- }
- }
-
- /*
- * ==================
- * CSGFaces
- *
- * Returns a list of surfaces containing aall of the faces
- * ==================
- */
- struct surface *CSGFaces(__memBase, struct brushset * bs)
- {
- struct brush *b1, *b2;
- int i, j;
- bool overwrite;
- struct visfacet *f;
- struct surface *surfhead;
-
- mprintf("----- CSGFaces ----------\n");
-
- /* added by niels */
- if(!(validfaces = (struct visfacet **)tmalloc(sizeof(struct visfacet *) * bspMem->numbrushplanes)))
- Error("CSGFaces: failed to allocate validfaces!\n");
-
- csgfaces = brushfaces = csgmergefaces = 0;
-
- Draw_ClearWindow();
-
- //
- // do the solid faces
- //
- for (b1 = bs->brushes, j = 0; b1; b1 = b1->next) {
- mprogress(bs->numbrushes, ++j);
-
- // set outside to a copy of the brush's faces
- CopyFacesToOutside(b1);
-
- overwrite = FALSE;
-
- for (b2 = bs->brushes; b2; b2 = b2->next) {
- // see if b2 needs to clip a chunk out of b1
-
- if (b1 == b2) {
- overwrite = TRUE; // later brushes now overwrite
-
- continue;
- }
-
- // check bounding box first
- for (i = 0; i < 3; i++)
- if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i])
- break;
- if (i < 3)
- continue;
-
- // divide faces by the planes of the new brush
-
- inside = outside;
- outside = NULL;
-
- for (f = b2->faces; f; f = f->next)
- ClipInside(bspMem, f->planenum, f->planeside, overwrite);
-
- // these faces are continued in another brush, so get rid of them
- if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER)
- FreeInside(b2->contents);
- else
- FreeInside(CONTENTS_SOLID);
- }
-
- // all of the faces left in outside are real surface faces
- if (b1->contents != CONTENTS_SOLID)
- SaveOutside(bspMem, TRUE); // mirror faces for inside view
-
- else
- SaveOutside(bspMem, FALSE);
- }
-
- #if 0
- if (!csgfaces)
- Error("No faces");
- #endif
-
- surfhead = BuildSurfaces(bspMem);
-
- mprintf("%5i brushfaces\n", brushfaces);
- mprintf("%5i csgfaces\n", csgfaces);
- mprintf("%5i mergedfaces\n", csgmergefaces);
-
- /* added by niels */
- tfree(validfaces);
- return surfhead;
- }
-